package dataMining.VertialTopK;

import java.io.*;

/**
 * @author: cuiH
 * Date: 13-7-8
 */

public class TopK {
    dataMining.VertialTopK.MyAlgorithm MA;

    void topK() throws IOException {
        //定义一个数组，存放item的第一次扫面的支持度,并且进行初始化
        int item[] = new int[MA.itemNumber];
        for (int i = 0; i < MA.itemNumber; i++) {
            item[i] = 0;
        }

        //首先进行文件的读取操作
        File inputFile = new File(MA.inputFile);                             //文件流
        FileReader fileReader = new FileReader(inputFile);                   //构造缓存
        BufferedReader bufferedReader = new BufferedReader(fileReader);      //文件存入缓存区域


        /*
        * 对boolean表进行赋值，
        * @param lineNumber 列号表示事务  rowNumber  行号表示itemID
        * step表示运行读了几次数据
        * 其中生成的二维表00行和列都是没用的
        * 而且uci数据集中换行前面还加有空格的ascii码，需要注意，也就是包含了两个字符
        * */
        int character;
        int lineNumber = 1;                                            //读取的时候表示transaction
        int rowNumber = 0;                                             // 表示itemId,item从一开始
        int step = 1;

        while ((character = bufferedReader.read()) != -1) {
            if (character == 32) {                                       //空格时候的情况
                step = 0;
                item[rowNumber]++;                                     //相应的支持度增加
                MA.DATA[rowNumber][lineNumber] = true;
                rowNumber = 0;                                         //赋值完成后开始重新读取一个数了
            } else if (character == 10) {                                //换行回车时候的情况
                step = 0;
                lineNumber++;
            } else if (character == 13) {                                //因为bat中的换行最后字符是一个13（enter）+10（换行）
            } else {
                if (step == 1) {                                         //读取数据结束，此时为两位数
                    rowNumber = character - 48;
                } else {                                   //此时数据时三位数
                    rowNumber = rowNumber * 10 + (character - 48);
                }
            }
            step++;
        }
        bufferedReader.close();//读取数据解说

        /*
        *  将所得到的支持度排入链表中,并将相应的位置，压入position中,生成最初的一项集列表
        * */

        MyLinkList linkList = new MyLinkList();
        for (int i = 1; i < MA.itemNumber; i++) {
            if (item[i] != 0) {
                linkList.add(new int[]{i}, item[i]);
            }
//            System.out.println(MA.position[MA.nowPosition]);
        }

//        /*
//        * 单元测试，测试数组的输出情况
//        * */
//        MyLinkList.Node node = linkList.top;
//        int p = 1;
//        while (node.next!= null) {
//            System.out.print(p + ": itemID:");
//            for(int i = 0;i<node.next.itemId.length;i++){
//                System.out.print(node.next.itemId[i]+" ");
//            }
//            System.out.println(",支持度:"+node.next.sup+"，位置为："+node.next.position);
//            p++;
//            node = node.next;
//        }

        /*
        * 基于链表进行连接操作 ,建立在初次赋值之后
        * 逻辑分析
        * top-》1-》2-》3.。。。依次向下走
        * outNode 作为外层循环，靠后
        * inNode  作为内层循环，靠前
        * */

        MyLinkList.Node outNode = linkList.top.next.next;                    //定位到2
        while (outNode.next != null) {                                          //这里默认包含有两个节点，一边进行操作
            MyLinkList.Node inNode = linkList.top;                      //从1开始
            while (inNode.next != outNode) {
                inNode = inNode.next;

                /*
                * 具体的连接操作,调用连接操作的方法
                * 目的：获取支持度
                * */
                int newSup = 0;
                Connect connect = new Connect();
                newSup = connect.connect(inNode.position, outNode.position);

                //如果支持度大于链表的最后一个元素的支持度，进行如下的操作
                if (newSup > linkList.getLastSup()) {
                    /*
                    * 进行具体插入的操作
                    * 目的：获取itemID
                    * */
                    int[] itemId = new int[inNode.itemId.length + outNode.itemId.length];
                    for (int i = 0; i < inNode.itemId.length; i++) {                 //读取内层
                        itemId[i] = inNode.itemId[i];                                 //直接赋值
                        if (i == inNode.itemId.length - 1) {                         //读取结束
                            int nodeLength = i;
                            for (int j = 0; j < outNode.itemId.length; j++) {        //读取外层
                                int m = 0;
                                while (outNode.itemId[j] != inNode.itemId[m]) {         //判定不相等
                                    if (m == i) {                                          //可以加入,比较完了所有外层循环
                                        itemId[++nodeLength] = outNode.itemId[j];              //加入
                                        break;
                                    }
                                    m++;
                                }
                            }
                        }
                    }

                    /*
                    * 先排除重复的的选项
                    * 然后对链表的具体插入,当存在支持度的时候，
                    * @后期可以对此处进行优化，大于最小支持度时候，再进行插入操作 （在获取itemId之前进行优化）
                    * 目的:获取具体位置，并且改变boolean表,获取对应的位置
                    * */
                    if (itemId[inNode.itemId.length + outNode.itemId.length - 1] != 0) {
                        linkList.add(itemId, newSup);
                        if (!linkList.isSame) {
                            int replacePosition = linkList.getReplaceLPosition();
                            for (int i = 1; i < MyAlgorithm.tranNumber; i++) {
                                if (MyAlgorithm.DATA[inNode.position][i] && MyAlgorithm.DATA[outNode.position][i]) {
                                    MyAlgorithm.DATA[replacePosition][i] = true;
                                } else {
                                    MyAlgorithm.DATA[replacePosition][i] = false;
                                }
                            }
                        }
                    }
                }
            }
            outNode = outNode.next;
        }

        //数据的输出部分
        File outFile = new File(MA.outputFile);
        FileWriter fileWriter = new FileWriter(outFile, true);
        fileWriter.write("得到的TOP" + (MA.K - 1) + "项集为：\r\n");
        MyLinkList.Node myLinkList = linkList.top.next;
        int n = 1;
        while (myLinkList.next != null) {
            fileWriter.write(n + ":");
            for (int i = 0; i < myLinkList.itemId.length; i++) {
                fileWriter.write(myLinkList.itemId[i] + ",");
            }
            fileWriter.write("支持度为：" + myLinkList.sup + "\r\n");
            myLinkList = myLinkList.next;
            n++;
        }
        fileWriter.close();
    }
}
